import { onMounted, type Ref, ref } from 'vue'

interface HookOptions<P = any, D = any> {
  /**
   * 是否自动请求，为true时，将在onMounted钩子自动执行一次getData
   */
  auto?: boolean

  loading?: Ref<boolean>

  params?: P

  success?: (res: D | undefined) => void
}

/**
 * 默认参数
 */
const defaultOptions: HookOptions = {
  auto: false
}

type FunctionParams<T> = T extends (arg: infer P) => any ? P : never

type ApiResult<T extends PromiseFn> = PromiseValue<ReturnType<T>>

export default function useRequest<
  API extends PromiseFn,
  D extends FunctionParams<API>
>(api: API, options?: HookOptions<D, ApiResult<API>>) {
  options = { ...defaultOptions, ...options }

  const loading = ref(false)
  const data = ref<PromiseValue<ReturnType<API>>>()

  // 切换loading状态
  function toggleLoading(flag: boolean) {
    loading.value = flag
    // 如果设置了自定义loading属性，则一起切换
    if (options?.loading !== undefined) {
      options.loading.value = flag
    }
  }

  // 获取数据
  async function request(
    params?: Partial<FunctionParams<API>>
  ): Promise<PromiseValue<ReturnType<API>>> {
    toggleLoading(true)
    try {
      const res = await api({
        ...options?.params,
        ...params
      })
      if (options?.success) {
        options.success(res)
      }
      data.value = res
      return res
    } finally {
      toggleLoading(false)
    }
  }

  onMounted(() => {
    if (options?.auto) {
      request()
    }
  })

  return {
    loading,
    data,
    request
  }
}
